#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define MAX_EVENTS 10
#define BUF_SIZE 1024
#define PORT 8888

// sudo ss -tulnp | grep 8888
// sudo kill -9 4859  # 强制终止


// 设置非阻塞模式
void setnonblocking(int sockfd) {
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
}

int main() {
    int server_fd, epoll_fd;
    struct sockaddr_in server_addr;
    struct epoll_event ev, events[MAX_EVENTS];
    char buffer[BUF_SIZE];
    
    // 创建服务器socket (IPv4, TCP)
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
    
    
    // 绑定服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    
    // 开始监听
    if (listen(server_fd, 5) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }
    
    printf("Server listening on port %d...\n", PORT);
    
    // 创建epoll实例

    epoll_fd = epoll_create1(0);     //  0 默认方式创建 epoll 实例，无特殊行为。
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }
    
    // 添加服务器socket到epoll
    ev.events = EPOLLIN;  // 监控可读事件 
    ev.data.fd = server_fd;  // 关联服务器 socket
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) {
        perror("epoll_ctl: server_fd");
        exit(EXIT_FAILURE);
    }
   

    while (1) {

        // 阻塞等待被监控的 fd 发生事件，返回就绪的事件列表。
        int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }
        
        for (int i = 0; i < nfds; i++) {
            // 处理新连接
            if (events[i].data.fd == server_fd) {
                struct sockaddr_in client_addr;
                socklen_t client_len = sizeof(client_addr);
                int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
                
                if (client_fd == -1) {
                    perror("accept");
                    continue;
                }

                 // 获取当前文件状态标志
                int flags = fcntl(client_fd, F_GETFL, 0);
                // 设置非阻塞标志
                fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);

                // 添加新客户端到epoll
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = client_fd;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
                    perror("epoll_ctl: client_fd");
                    close(client_fd);
                    continue;
                }
                
            } 
            // 处理客户端数据
            else {
                int client_fd = events[i].data.fd;
                ssize_t read_size = read(client_fd, buffer, BUF_SIZE);
                
                if (read_size <= 0) {
                    //断开连接
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
                    close(client_fd);
                    printf("Client disconnected\n");
                } else {
                    //接收到的消息
                    buffer[read_size] = '\0';
                    printf("client %d Say: %s",client_fd, buffer);
                    write(client_fd, buffer, read_size);
                }
            }
        }
    }
    
    close(server_fd);
    return 0;
}
